type MyReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

interface TestTodo {
  title: string;
  description: string
}

const todoA: MyReadonly<TestTodo> = {
  title: 'string',
  description: 'string'
}

type MyReadonly2<T, U> = U extends keyof T ? {
  readonly [K in U]: T[K];
} & { [K in Exclude<keyof T, U>]: T[K] } : Readonly<T>

interface TestTodo2 {
  title: string
  description: string
  completed: boolean
}

type RRR = MyReadonly2<TestTodo2, 'title'>

const todoB: MyReadonly2<Todo, 'title' | 'description'> = {
  title: "Hey",
  description: "foobar",
  completed: false,
}

// todoB.title = "Hello" // Error: cannot reassign a readonly property
// todoB.description = "barFoo" // Error: cannot reassign a readonly property
todoB.completed = true // OK

type X = {
  x: {
    a: 1
    b: 'hi',
    c: {
      d: '1'
    }
  }
  y: 'hey'
}

type Expected = {
  readonly x: {
    readonly a: 1
    readonly b: 'hi'
  }
  readonly y: 'hey'
}

type TodoDeepReadonly = DeepReadonly<X> // should be same as `Expected`

type DeepReadonly<X> = X extends object ? {
  readonly [K in keyof X]: DeepReadonly<X[K]>
} : X